const app = require('express').Router()
const { spawn } = require('child_process');
const fs = require('fs');
const fsExtra = require('fs-extra');

// 获取当前时间
let getTimeNow = () => {
  const now = new Date();

  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0');
  const day = String(now.getDate()).padStart(2, '0');
  const hours = String(now.getHours()).padStart(2, '0');
  const minutes = String(now.getMinutes()).padStart(2, '0');
  const seconds = String(now.getSeconds()).padStart(2, '0');

  const formattedTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  return formattedTime
}

// 根据id往日志表中存日志
let saveLog = (id, data) => {
  const formattedTime = getTimeNow()
  let log = `${formattedTime} ${data}`
  const insterQuery = `INSERT INTO ${global.myConfig.pool.logTable} (id,time,log) VALUES ($1,$2,$3)`
  const time = new Date().getTime()
  const values = [id, time, log]
  global.pool.query(insterQuery, values, (err, result) => {
    if (err) {
      console.error('日志插入出错:', err);
      return;
    }
  });
}

// 调用exe转换osgb
let callExeFromOsgb = async (body, tempDir, id) => {
  const convertOSGB = global.myConfig.toolConfiguration.convertOSGB
  // 指定文件夹路径和要执行的命令
  const folderPath = convertOSGB.url;
  const command = `${convertOSGB.name} -C ${convertOSGB.config}`;
  // 执行打开命令行终端并执行命令的操作
  const cmd = spawn('cmd', ['/C', command], { cwd: folderPath });
  // 监听命令行输出
  cmd.stdout.on('data', (data) => {
    saveLog(id, data)
  });
  // 监听命令行错误输出
  cmd.stderr.on('data', (data) => {
    console.error(`错误：${data}`);
    saveLog(id, data)
  });
  // 监听命令行关闭事件
  cmd.on('close', (code) => {
    if (code == 0) {
      const data = '临时文件转换成功'
      console.log(data);
      saveLog(id, data)
      writeInCompress(body, tempDir, id, convertOSGB.compress)
    } else if (code == 1) {
      const data = '转换错误'
      console.log(data);
      saveLog(id, data)
    } else if (code == 2) {
      const data = '命令行参数不正确'
      console.log(data);
      saveLog(id, data)
    } else if (code == 127) {
      const data = '命令不存在或无法执行'
      console.log(data);
      saveLog(id, data)
    } else if (code == 128) {
      const data = '命令被终止'
      console.log(data);
      saveLog(id, data)
    }
  });
}

// 写入compress的config
let writeInCompress = async (body, tempDir, id, compress) => {
  const { tileRootDir, mode, useCompression } = body
  fs.readFile(`${compress.url}/${compress.config}`, 'utf8', (err, data) => {
    if (err) {
      console.error(err)
      return
    }
    let jsonData = JSON.parse(data)
    jsonData.tileDir = tempDir
    jsonData.compressDir = tileRootDir + '\\3dtiles'
    if (!fs.existsSync(tileRootDir + '\\3dtiles')) {
      fs.mkdirSync(tileRootDir + '\\3dtiles');
    }
    if (mode !== undefined) {
      jsonData.mode = mode
    }
    if (useCompression !== undefined) {
      jsonData.compressOptions.texture_compression_options.use_compression = useCompression
      jsonData.compressOptions.max_level_texture_compression_options.use_compression = useCompression
    }
    const updateData = JSON.stringify(jsonData)
    fs.writeFile(`${compress.url}/${compress.config}`, updateData, 'utf8', (err) => {
      if (err) {
        console.error(err);
        return;
      }
      console.log('config.json写入成功')
      callExeTo3Dtiles(id, compress)
    })
  })
}

// 调用exe转化为3dtiles
let callExeTo3Dtiles = async (id, compress) => {
  // 指定文件夹路径和要执行的命令
  const folderPath = compress.url;
  const command = `${compress.name} -C ${compress.config}`;
  // 执行打开命令行终端并执行命令的操作
  const cmd = spawn('cmd', ['/C', command], { cwd: folderPath });
  // 监听命令行输出
  cmd.stdout.on('data', (data) => {
    saveLog(id, data)
  });
  // 监听命令行错误输出
  cmd.stderr.on('data', (data) => {
    console.error(`错误：${data}`);
    saveLog(id, data)
  });
  // 监听命令行关闭事件
  cmd.on('close', (code) => {
    if (code == 0) {
      saveLog(id, '转换成功')
      global.pool.query(`UPDATE ${global.myConfig.pool.serviceTable} SET section = 1 WHERE id = '${id}'`, (err, result) => {
        if (err) {
          console.error('查询数据出错:', err);
          return;
        } else {
          console.log('数据修改成功')
        }
      });
    } else if (code == 1) {
      const data = '转换错误'
      console.log(data);
      saveLog(id, data)
    } else if (code == 2) {
      const data = '命令行参数不正确'
      console.log(data);
      saveLog(id, data)
    } else if (code == 127) {
      const data = '命令不存在或无法执行'
      console.log(data);
      saveLog(id, data)
    } else if (code == 128) {
      const data = '命令被终止'
      console.log(data);
      saveLog(id, data)
    }
  });
}

// 调用exe转换obj
let callExeFromObj = async (body, tempDir, id) => {
  const convertOBJ = global.myConfig.toolConfiguration.convertOBJ
  // 指定文件夹路径和要执行的命令
  const folderPath = convertOBJ.url;
  const command = `${convertOBJ.name} -C ${convertOBJ.config}`;
  // 执行打开命令行终端并执行命令的操作
  const cmd = spawn('cmd', ['/C', command], { cwd: folderPath });
  // 监听命令行输出
  cmd.stdout.on('data', (data) => {
    saveLog(id, data)
  });
  // 监听命令行错误输出
  cmd.stderr.on('data', (data) => {
    console.error(`错误：${data}`);
    saveLog(id, data)
  });
  // 监听命令行关闭事件
  cmd.on('close', (code) => {
    if (code == 0) {
      const data = '临时文件转换成功'
      console.log(data);
      saveLog(id, data)
      writeInCompress(body, tempDir, id, convertOBJ.compress)
    } else if (code == 1) {
      const data = '转换错误'
      console.log(data);
      saveLog(id, data)
    } else if (code == 2) {
      const data = '命令行参数不正确'
      console.log(data);
      saveLog(id, data)
    } else if (code == 127) {
      const data = '命令不存在或无法执行'
      console.log(data);
      saveLog(id, data)
    } else if (code == 128) {
      const data = '命令被终止'
      console.log(data);
      saveLog(id, data)
    }
  });
}

// 调用exe转换glb_3dtiles
let callExeFromLasToGlb = async (body, tempDir, id) => {
  const convertLAStoGLB = global.myConfig.toolConfiguration.convertLAStoGLB
  // 指定文件夹路径和要执行的命令
  const folderPath = convertLAStoGLB.url;
  const command = `${convertLAStoGLB.name} -C ${convertLAStoGLB.config}`;
  // 执行打开命令行终端并执行命令的操作
  const cmd = spawn('cmd', ['/C', command], { cwd: folderPath });
  // 监听命令行输出
  cmd.stdout.on('data', (data) => {
    saveLog(id, data)
  });
  // 监听命令行错误输出
  cmd.stderr.on('data', (data) => {
    console.error(`错误：${data}`);
    saveLog(id, data)
  });
  // 监听命令行关闭事件
  cmd.on('close', (code) => {
    if (code == 0) {
      const data = '临时文件转换成功'
      console.log(data);
      saveLog(id, data)
      writeInLasCompress(body, tempDir, id, convertLAStoGLB.compress)
    } else if (code == 1) {
      const data = '转换错误'
      console.log(data);
      saveLog(id, data)
    } else if (code == 2) {
      const data = '命令行参数不正确'
      console.log(data);
      saveLog(id, data)
    } else if (code == 127) {
      const data = '命令不存在或无法执行'
      console.log(data);
      saveLog(id, data)
    } else if (code == 128) {
      const data = '命令被终止'
      console.log(data);
      saveLog(id, data)
    }
  });
}

// 调用exe转换pnts_3dtiles
let callExeFromLasToPnts = async (body, tempDir, id) => {
  const convertLAStoPNTS = global.myConfig.toolConfiguration.convertLAStoPNTS
  // 指定文件夹路径和要执行的命令
  const folderPath = convertLAStoPNTS.url;
  const command = `${convertLAStoPNTS.name} -C ${convertLAStoPNTS.config}`;
  // 执行打开命令行终端并执行命令的操作
  const cmd = spawn('cmd', ['/C', command], { cwd: folderPath });
  // 监听命令行输出
  cmd.stdout.on('data', (data) => {
    saveLog(id, data)
  });
  // 监听命令行错误输出
  cmd.stderr.on('data', (data) => {
    console.error(`错误：${data}`);
    saveLog(id, data)
  });
  // 监听命令行关闭事件
  cmd.on('close', (code) => {
    if (code == 0) {
      const data = '临时文件转换成功'
      console.log(data);
      saveLog(id, data)
      writeInLasCompress(body, tempDir, id, convertLAStoPNTS.compress)
    } else if (code == 1) {
      const data = '转换错误'
      console.log(data);
      saveLog(id, data)
    } else if (code == 2) {
      const data = '命令行参数不正确'
      console.log(data);
      saveLog(id, data)
    } else if (code == 127) {
      const data = '命令不存在或无法执行'
      console.log(data);
      saveLog(id, data)
    } else if (code == 128) {
      const data = '命令被终止'
      console.log(data);
      saveLog(id, data)
    }
  });
}

// 写入Las的compress的config
let writeInLasCompress = async (body, tempDir, id, compress) => {
  const { tilesDir } = body
  fs.readFile(`${compress.url}/${compress.config}`, 'utf8', (err, data) => {
    if (err) {
      console.error(err)
      return
    }
    let jsonData = JSON.parse(data)
    jsonData.tileDir = tempDir
    jsonData.compressDir = tilesDir + '\\3dtiles'
    if (!fs.existsSync(tilesDir + '\\3dtiles')) {
      fs.mkdirSync(tilesDir + '\\3dtiles');
    }
    const updateData = JSON.stringify(jsonData)
    fs.writeFile(`${compress.url}/${compress.config}`, updateData, 'utf8', (err) => {
      if (err) {
        console.error(err);
        return;
      }
      console.log('config.json写入成功')
      callExeFromLasTo3Dtiles(id, compress)
    })
  })
}

// 调用exe把Las转换成3dtiles
let callExeFromLasTo3Dtiles = async (id, compress) => {
  // 指定文件夹路径和要执行的命令
  const folderPath = compress.url;
  const command = `${compress.name} -C ${compress.config}`;
  // 执行打开命令行终端并执行命令的操作
  const cmd = spawn('cmd', ['/C', command], { cwd: folderPath });
  // 监听命令行输出
  cmd.stdout.on('data', (data) => {
    saveLog(id, data)
  });
  // 监听命令行错误输出
  cmd.stderr.on('data', (data) => {
    console.error(`错误：${data}`);
    saveLog(id, data)
  });
  // 监听命令行关闭事件
  cmd.on('close', (code) => {
    if (code == 0) {
      const data = '转换成功'
      console.log(data)
      saveLog(id, data)
      global.pool.query(`UPDATE ${global.myConfig.pool.serviceTable} SET section = 1 WHERE id = '${id}'`, (err, result) => {
        if (err) {
          console.error('查询数据出错:', err);
          return;
        } else {
          console.log('数据修改成功')
        }
      });
    } else if (code == 1) {
      const data = '转换错误'
      console.log(data);
      saveLog(id, data)
    } else if (code == 2) {
      const data = '命令行参数不正确'
      console.log(data);
      saveLog(id, data)
    } else if (code == 127) {
      const data = '命令不存在或无法执行'
      console.log(data);
      saveLog(id, data)
    } else if (code == 128) {
      const data = '命令被终止'
      console.log(data);
      saveLog(id, data)
    }
  });
}

// 调用exe转换通用模型
let callExeFromCommon = async (id, compress) => {
  // 指定文件夹路径和要执行的命令
  const folderPath = compress.url;
  const command = `${compress.name} -C ${compress.config}`;
  // 执行打开命令行终端并执行命令的操作
  const cmd = spawn('cmd', ['/C', command], { cwd: folderPath });
  // 监听命令行输出
  cmd.stdout.on('data', (data) => {
    saveLog(id, data)
  });
  // 监听命令行错误输出
  cmd.stderr.on('data', (data) => {
    console.error(`错误：${data}`);
    saveLog(id, data)
  });
  // 监听命令行关闭事件
  cmd.on('close', (code) => {
    if (code == 0) {
      const data = '转换成功'
      console.log(data)
      saveLog(id, data)
      global.pool.query(`UPDATE ${global.myConfig.pool.serviceTable} SET section = 1 WHERE id = '${id}'`, (err, result) => {
        if (err) {
          console.error('查询数据出错:', err);
          return;
        } else {
          console.log('数据修改成功')
        }
      });
    } else if (code == 1) {
      const data = '转换错误'
      console.log(data);
      saveLog(id, data)
    } else if (code == 2) {
      const data = '命令行参数不正确'
      console.log(data);
      saveLog(id, data)
    } else if (code == 127) {
      const data = '命令不存在或无法执行'
      console.log(data);
      saveLog(id, data)
    } else if (code == 128) {
      const data = '命令被终止'
      console.log(data);
      saveLog(id, data)
    }
  });
}

// 调用接口写入json并调用exe来转换osgb到3dtiles
app.post('/updateOsgbTo3DtilesConfig', async (req, res) => {
  const { osgRootDir, tileRootDir, reCreateNormal, simplifyThreshold, mergeGridTileThreshold, id, simplify, textureQuality } = req.body
  const convertOSGB = global.myConfig.toolConfiguration.convertOSGB
  fs.readFile(`${convertOSGB.url}/${convertOSGB.config}`, 'utf8', (err, data) => {
    if (err) {
      console.error(err);
      return;
    }
    // 解析 JSON 数据
    let jsonData = JSON.parse(data);
    let tempDir = tileRootDir + '\\tilec'
    if (!fs.existsSync(tempDir)) {
      fs.mkdirSync(tempDir);
    }
    // 修改 JSON 数据
    jsonData.osgRootDir = osgRootDir;
    jsonData.tileRootDir = tempDir;
    jsonData.options.reCreateNormal = reCreateNormal
    jsonData.options.textureQuality = textureQuality
    jsonData.options.simplify = simplify
    jsonData.merge.mergeGridTileThreshold = mergeGridTileThreshold
    if (simplifyThreshold) {
      jsonData.merge.simplifyThreshold = simplifyThreshold
    }
    // 将 JSON 数据转换为字符串
    const updatedData = JSON.stringify(jsonData);
    // 写入 JSON 文件
    fs.writeFile(`${convertOSGB.url}/${convertOSGB.config}`, updatedData, 'utf8', (err) => {
      if (err) {
        console.error(err);
        return;
      }
      console.log('OsgTo3DtilesConfig.json写入成功')
      callExeFromOsgb(req.body, tempDir, id)
      res.json({
        status: 200,
        msg: "OSGB转3Dtiles任务已创建成功"
      })
    });
  });
})

// 调用接口写入json并调用exe来转换OBJ到3dtiles
app.post('/updateObjTo3DtilesConfig', async (req, res) => {
  const { objRootDir, tileRootDir, upAxisYToZ, mergeTexture, level, id } = req.body
  const convertOBJ = global.myConfig.toolConfiguration.convertOBJ
  fs.readFile(`${convertOBJ.url}/${convertOBJ.config}`, 'utf8', (err, data) => {
    if (err) {
      console.error(err);
      return;
    }
    // 解析 JSON 数据
    let jsonData = JSON.parse(data);
    let tempDir = tileRootDir + '\\tilec'
    if (!fs.existsSync(tempDir)) {
      fs.mkdirSync(tempDir);
    }
    // 修改 JSON 数据
    jsonData.objRootDir = objRootDir;
    jsonData.tileRootDir = tempDir;
    jsonData.options.upAxisYToZ = upAxisYToZ
    jsonData.options.buildGridTileConfig = {}
    let levels = level.split('-')
    if (levels.length > 1) {
      let textureRatio = 1
      for (let i = parseInt(levels[1]); i >= parseInt(levels[0]); i = i - 1) {
        jsonData.options.buildGridTileConfig[i] = {
          mergeTinyGlb: true,
          mergeTexture: i == parseInt(levels[1]) ? false : mergeTexture,
          separateResources: false,
          textureRatio: textureRatio
        }
        textureRatio = textureRatio / 2
      }
    } else {
      jsonData.options.buildGridTileConfig[levels[0]] = {
        mergeTinyGlb: false,
        mergeTexture: false,
        separateResources: false,
        textureRatio: 1
      }
    }
    // 将 JSON 数据转换为字符串
    const updatedData = JSON.stringify(jsonData);
    // 写入 JSON 文件
    fs.writeFile(`${convertOBJ.url}/${convertOBJ.config}`, updatedData, 'utf8', (err) => {
      if (err) {
        console.error(err);
        return;
      }
      callExeFromObj(req.body, tempDir, id)
      console.log('config.json写入成功')
      res.json({
        status: 200,
        msg: "OBJ转3Dtiles任务已创建成功"
      })
    });
  })
})

// 调用接口写入json并调用exe来转换las到glb_3dtiles
app.post('/updateLasTo3DtilesConfig', async (req, res) => {
  try {
    const { lasFileDir, tilesDir, maxLevel, density, id, type, uploadFileType } = req.body
    if (uploadFileType == 'las') {
      if (type == 'glb') {
        const convertLAStoGLB = global.myConfig.toolConfiguration.convertLAStoGLB
        fs.readFile(`${convertLAStoGLB.url}/${convertLAStoGLB.config}`, 'utf8', (err, data) => {
          if (err) {
            console.error(err);
            return;
          }
          // 解析 JSON 数据
          let jsonData = JSON.parse(data);
          let tempDir = tilesDir + '\\tilec'
          if (!fs.existsSync(tempDir)) {
            fs.mkdirSync(tempDir);
          }
          // 修改 JSON 数据
          jsonData.lasFileDir = lasFileDir
          jsonData.tilesDir = tempDir
          jsonData.maxLevel = maxLevel
          jsonData.options.density = density
          // 将 JSON 数据转换为字符串
          const updatedData = JSON.stringify(jsonData);
          // 写入 JSON 文件
          fs.writeFile(`${convertLAStoGLB.url}/${convertLAStoGLB.config}`, updatedData, 'utf8', (err) => {
            if (err) {
              console.error(err);
              return;
            }
            console.log('Config.json写入成功')
            callExeFromLasToGlb(req.body, tempDir, id)
            res.json({
              status: 200,
              msg: "LAS转GLB_3Dtiles任务已创建成功"
            })
          });
        })
      }
      if (type == 'pnts') {
        const convertLAStoPNTS = global.myConfig.toolConfiguration.convertLAStoPNTS
        fs.readFile(`${convertLAStoPNTS.url}/${convertLAStoPNTS.config}`, 'utf8', (err, data) => {
          if (err) {
            console.error(err);
            return;
          }
          // 解析 JSON 数据
          let jsonData = JSON.parse(data);
          let tempDir = tilesDir + '\\tilec'
          if (!fs.existsSync(tempDir)) {
            fs.mkdirSync(tempDir);
          }
          // 修改 JSON 数据
          jsonData.lasFileDir = lasFileDir
          jsonData.tilesDir = tempDir
          jsonData.maxLevel = maxLevel
          jsonData.options.density = density
          // 将 JSON 数据转换为字符串
          const updatedData = JSON.stringify(jsonData);
          // 写入 JSON 文件
          fs.writeFile(`${convertLAStoPNTS.url}/${convertLAStoPNTS.config}`, updatedData, 'utf8', (err) => {
            if (err) {
              console.error(err);
              return;
            }
            console.log('Config.json写入成功')
            callExeFromLasToPnts(req.body, tempDir, id)
            res.json({
              status: 200,
              msg: "LAS转GLB_3Dtiles任务已创建成功"
            })
          });
        })
      }
    } else {
      // 如果转换的文件类型是pnts，直接压缩
      const convertLAStoPNTS = global.myConfig.toolConfiguration.convertLAStoPNTS
      writeInLasCompress(req.body, lasFileDir, id, convertLAStoPNTS.compress)
      res.json({
        status: 200,
        msg: "pnts压缩任务已创建成功"
      })
    }
  } catch (error) {
    console.log(error)
    res.send(error)
  }
})

// 调用转换通用模型工具
app.post('/transformCommonModel', async (req, res) => {
  let { glbInDir, glbOutDir, upAxisYToZ, textureThreshold, mergeTexture, toType, id } = req.body
  let convertBeCommon = global.myConfig.toolConfiguration.convertBeCommon
  fs.readFile(`${convertBeCommon.url}/${convertBeCommon.config}`, 'utf8', (err, data) => {
    if (err) {
      console.error(err);
      return;
    }
    // 解析 JSON 数据
    let jsonData = JSON.parse(data);
    if (!fs.existsSync(glbOutDir + '\\3dtiles')) {
      fs.mkdirSync(glbOutDir + '\\3dtiles');
    }
    // 修改 JSON 数据
    jsonData.glbInDir = glbInDir;
    jsonData.glbOutDir = glbOutDir + '\\3dtiles';
    jsonData.upAxisYToZ = upAxisYToZ
    jsonData.textureThreshold = textureThreshold
    jsonData.mergeTexture = mergeTexture
    jsonData.toType = toType
    // 将 JSON 数据转换为字符串
    const updatedData = JSON.stringify(jsonData);
    // 写入 JSON 文件
    fs.writeFile(`${convertBeCommon.url}/${convertBeCommon.config}`, updatedData, 'utf8', (err) => {
      if (err) {
        console.error(err);
        return;
      }
      callExeFromCommon(id, convertBeCommon)
      console.log('config.json写入成功')
      res.json({
        status: 200,
        msg: "通用模型转换任务已创建成功"
      })
    });
  })
})

module.exports = app;